from django.shortcuts import render, get_object_or_404, redirect
from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
# Create your views here.
from .models import Book, Author, BookInstance, Genre, BookRating, BookReview, BookLike, BookFavorite, FavoriteGroup, ReviewLike, ReviewFavorite, ReviewComment, Profile, ChatMessage
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.urls import reverse, reverse_lazy
import datetime

from django.utils.translation import gettext_lazy as _
from django.views import generic
from .forms import RenewBookForm, RatingForm, ReviewForm, ProfileForm,RegisterForm
from django.db.models import Avg
from django.db.models import Count
from django.db.models import Q
from django.core.paginator import Paginator
from django.contrib import messages
import csv
from django.http import HttpResponse
import openpyxl
from openpyxl.utils import get_column_letter
from django import forms
from django.db.models import Max
from django.http import JsonResponse
from .ai import ai_service
import json
from django.db.models import Prefetch, OuterRef, Subquery
from django.views.decorators.http import require_POST

def home_page(request):
    """
    View function for the main home page.
    """
    return render(
        request,
        'home.html',
        context={}
    )

def index(request):
    """
    View function for home page of site.
    """
    # Generate counts of some of the main objects
    num_books=Book.objects.all().count()
    num_instances=BookInstance.objects.all().count()
    # Available books (status = 'a')
    num_instances_available=BookInstance.objects.filter(status__exact='a').count()
    num_authors=Author.objects.count()  # The 'all()' is implied by default.

    # Number of visits to this view, as counted in the session variable.
    num_visits = request.session.get('num_visits', 0)
    request.session['num_visits'] = num_visits + 1
    # Render the HTML template index.html with the data in the context variable
    return render(
        request,
        'index.html',
        context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors,
            'num_visits':num_visits}, # num_visits appended
    )

class BookListView(generic.ListView):
    model = Book
    paginate_by = 6 # Set to 6 to display 6 books per page

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get the context
        context = super(BookListView, self).get_context_data(**kwargs)
        # Create any data and add it to the context
        context['some_data'] = 'This is just some data'
        if self.request.user.is_authenticated:
            context['favorite_groups'] = self.request.user.favorite_groups.all()
        else:
            context['favorite_groups'] = []
        return context

def book_detail_view(request, pk):
    book_id = get_object_or_404(Book, pk=pk)
    user_rating = None
    review_form = None
    user_has_liked = False
    user_has_favorited = False

    if request.user.is_authenticated:
        user_has_liked = BookLike.objects.filter(book=book_id, user=request.user).exists()
        user_has_favorited = BookFavorite.objects.filter(book=book_id, user=request.user).exists()

        if request.method == 'POST' and 'review_submit' in request.POST:
            review_form = ReviewForm(request.POST)
            if review_form.is_valid():
                BookReview.objects.create(
                    book=book_id,
                    user=request.user,
                    content=review_form.cleaned_data['content']
                )
                return redirect(request.path)
        elif request.method == 'POST':
            form = RatingForm(request.POST)
            if form.is_valid():
                rating_value = int(form.cleaned_data['rating'])
                BookRating.objects.update_or_create(
                    book=book_id, user=request.user,
                    defaults={'rating': rating_value}
                )
        else:
            form = RatingForm()
            try:
                user_rating = BookRating.objects.get(book=book_id, user=request.user).rating
            except BookRating.DoesNotExist:
                user_rating = None
        if not review_form:
            review_form = ReviewForm()
    else:
        form = None
        review_form = None

    avg_rating = book_id.ratings.aggregate(Avg('rating'))['rating__avg']
    
    # Initialize prefetch_queries list
    prefetch_queries = []

    if request.user.is_authenticated:
        prefetch_queries.append(Prefetch('likes', queryset=ReviewLike.objects.filter(user=request.user), to_attr='user_likes'))
        prefetch_queries.append(Prefetch('favorites', queryset=ReviewFavorite.objects.filter(user=request.user), to_attr='user_favorites'))

    reviews = BookReview.objects.filter(book=book_id).select_related('user').prefetch_related(
        *prefetch_queries, # Unpack the list of prefetch objects here
        Prefetch('comments', queryset=ReviewComment.objects.filter(parent_comment__isnull=True).select_related('user').prefetch_related(
            Prefetch('replies', queryset=ReviewComment.objects.select_related('user'), to_attr='all_replies')
        ), to_attr='top_level_comments')
    ).order_by('-created_at')

    return render(
        request,
        'catalog/book_detail.html',
        context={'book': book_id, 'form': form, 'user_rating': user_rating, 'avg_rating': avg_rating, 'review_form': review_form, 'reviews': reviews, 'user_has_liked': user_has_liked, 'user_has_favorited': user_has_favorited}
    )


def register(request):
    if request.method == 'GET':
        form = RegisterForm()
        return render(
            request,
            'registration/register.html',
            {"form": form}
        )

    elif request.method == 'POST':
        # 获取参数
        form = RegisterForm(request.POST)
        user_name = request.POST.get('username', '')
        pwd = request.POST.get('password', '')
        email = request.POST.get('email', '')
        print(user_name, pwd, email)

        # 用户已存在
        if User.objects.filter(username=user_name):
            clear_errors = _("account is exist!")
            return render(
                request,
                "registration/register.html",
                {"form": form, "clear_errors": clear_errors}
            )
        # 用户不存在
        else:
            # 使用User内置方法创建用户
            user = User.objects.create_user(
                username=user_name,
                password=pwd,
                email=email,
                is_staff=0,
                is_active=1,
                is_superuser=0
            )

            return redirect("/accounts/login/")

    else:
        return JsonResponse({
            'code': 403,
            'msg': '被禁止的请求'
        })

class AuthorListView(generic.ListView):
    """
    Generic class-based view for a list of authors.
    """
    model = Author
    paginate_by = 6 # Set to 6 to display 6 authors per page


class AuthorDetailView(generic.DetailView):
    """
    Generic class-based detail view for an author.
    """
    model = Author
    paginate_by = 6

class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
    """
    Generic class-based view listing books on loan to current user.
    """
    model = BookInstance
    template_name ='catalog/bookinstance_list_borrowed_user.html'
    paginate_by = 10

    def get_queryset(self):
        return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')

class BorrowedBooksListView(generic.ListView, PermissionRequiredMixin):
    """
    Generic class-based view listing all borrowed books.
    Only visible to users with can_mark_returned permission."""
    model = BookInstance
    permission_required = 'catalog.can_mark_returned'
    template_name = 'catalog/bookinstance_list_borrowed_librarian.html'
    paginate_by = 10

    def get_queryset(self):
        # Filter by book instances that are not available
        return BookInstance.objects.filter(status__exact='o').order_by('due_back')

def renew_book_librarian(request, pk):
    """
    View function for renewing a specific BookInstance by librarian
    """
    # Manual permission check
    if not request.user.has_perm('catalog.can_mark_returned'):
        return HttpResponseForbidden("You do not have permission to renew books.")

    book_inst=get_object_or_404(BookInstance, pk = pk)

    # If this is a POST request then process the Form data
    if request.method == 'POST':

        # Create a form instance and populate it with data from the request (binding):
        form = RenewBookForm(request.POST)

        # Check if the form is valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
            book_inst.due_back = form.cleaned_data['renewal_date']
            book_inst.save()

            # redirect to a new URL:
            return HttpResponseRedirect(reverse('catalog:all-borrowed') )
        else:
            # If form is not valid, render the template with the form and errors
            return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst': book_inst})

    # If this is a GET (or any other method) create the default form.
    else:
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})

    # Render the template for GET requests
    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})

class AuthorCreate(generic.CreateView):
    model = Author
    fields = '__all__'

class AuthorUpdate(generic.UpdateView):
    model = Author
    fields = ['first_name', 'last_name', 'date_of_birth', 'date_of_death']

class AuthorDelete(generic.DeleteView):
    model = Author
    success_url = reverse_lazy('authors')

class BookCreate(generic.CreateView):
    model = Book
    fields = '__all__'

class BookUpdate(generic.UpdateView):
    model = Book
    fields = '__all__' # Or specify a list of fields like for AuthorUpdate

class BookDelete(generic.DeleteView):
    model = Book
    success_url = reverse_lazy('catalog:books') # Redirect to the book list after deletion

def book_borrow_ranking(request):
    books = Book.objects.annotate(
        borrowed_count=Count('bookinstance', filter=Q(bookinstance__status__in=['o', 'a'])),
        avg_rating=Avg('ratings__rating')
    ).order_by('-borrowed_count')[:10]
    return render(request, 'catalog/book_borrow_ranking.html', {'books': books})

@login_required
def like_book(request, pk):
    book = get_object_or_404(Book, pk=pk)
    BookLike.objects.get_or_create(book=book, user=request.user)
    return redirect('catalog:book-detail', pk=pk)

@login_required
def unlike_book(request, pk):
    book = get_object_or_404(Book, pk=pk)
    BookLike.objects.filter(book=book, user=request.user).delete()
    return redirect('catalog:book-detail', pk=pk)

@login_required
def favorite_book(request, pk):
    book = get_object_or_404(Book, pk=pk)
    BookFavorite.objects.get_or_create(book=book, user=request.user)
    return redirect('catalog:book-detail', pk=pk)

@login_required
def unfavorite_book(request, pk):
    book = get_object_or_404(Book, pk=pk)
    BookFavorite.objects.filter(book=book, user=request.user).delete()
    return redirect('catalog:book-detail', pk=pk)

@login_required
def like_review(request, pk):
    review = get_object_or_404(BookReview, pk=pk)
    if request.method == 'POST':
        ReviewLike.objects.get_or_create(review=review, user=request.user)
        return JsonResponse({'status': 'success', 'likes': review.likes.count()})
    return JsonResponse({'status': 'fail', 'message': 'Invalid request method'}, status=405)

@login_required
def unlike_review(request, pk):
    review = get_object_or_404(BookReview, pk=pk)
    if request.method == 'POST':
        ReviewLike.objects.filter(review=review, user=request.user).delete()
        return JsonResponse({'status': 'success', 'likes': review.likes.count()})
    return JsonResponse({'status': 'fail', 'message': 'Invalid request method'}, status=405)

@login_required
def favorite_review(request, pk):
    review = get_object_or_404(BookReview, pk=pk)
    if request.method == 'POST':
        ReviewFavorite.objects.get_or_create(review=review, user=request.user)
        return JsonResponse({'status': 'success', 'favorites': review.favorites.count()})
    return JsonResponse({'status': 'fail', 'message': 'Invalid request method'}, status=405)

@login_required
def unfavorite_review(request, pk):
    review = get_object_or_404(BookReview, pk=pk)
    if request.method == 'POST':
        ReviewFavorite.objects.filter(review=review, user=request.user).delete()
        return JsonResponse({'status': 'success', 'favorites': review.favorites.count()})
    return JsonResponse({'status': 'fail', 'message': 'Invalid request method'}, status=405)

@login_required
@require_POST
def comment_review(request, pk):
    review = get_object_or_404(BookReview, pk=pk)
    try:
        data = json.loads(request.body)
        content = data.get('content')
        parent_comment_id = data.get('parent_comment_id')
    except json.JSONDecodeError:
        return JsonResponse({'error': 'Invalid JSON'}, status=400)

    if not content:
        return JsonResponse({'error': 'Comment content cannot be empty'}, status=400)

    parent_comment = None
    if parent_comment_id:
        try:
            parent_comment = ReviewComment.objects.get(id=parent_comment_id, review=review)
        except ReviewComment.DoesNotExist:
            return JsonResponse({'error': 'Parent comment not found'}, status=404)

    comment = ReviewComment.objects.create(
        review=review,
        user=request.user,
        content=content,
        parent_comment=parent_comment
    )
    return JsonResponse({
        'id': comment.id,
        'user': comment.user.username,
        'content': comment.content,
        'created_at': comment.created_at.strftime('%Y-%m-%d %H:%M'),
        'parent_comment_id': parent_comment_id
    }, status=201)

class FavoriteGroupForm(forms.ModelForm):
    class Meta:
        model = FavoriteGroup
        fields = ['name']

@login_required
def manage_favorite_groups(request):
    groups = request.user.favorite_groups.all().order_by('order') # Order by 'order' field
    if request.method == 'POST':
        form = FavoriteGroupForm(request.POST)
        if form.is_valid():
            group = form.save(commit=False)
            group.user = request.user
            # Set initial order for new group
            max_order = FavoriteGroup.objects.filter(user=request.user).aggregate(Max('order'))['order__max']
            group.order = (max_order or 0) + 1
            group.save()
            messages.success(request, _("Group created successfully!"))
            return redirect('manage-favorite-groups')
    else:
        form = FavoriteGroupForm()
    return render(request, 'catalog/manage_favorite_groups.html', {'groups': groups, 'form': form})

@login_required
def delete_favorite_group(request, pk):
    group = get_object_or_404(FavoriteGroup, pk=pk, user=request.user)
    if request.method == 'POST':
        group.delete()
        messages.success(request, _("Group deleted successfully!"))
        return redirect('catalog:manage-favorite-groups')
    return render(request, 'catalog/delete_favorite_group.html', {'group': group})

@login_required
def rename_favorite_group(request, pk):
    group = get_object_or_404(FavoriteGroup, pk=pk, user=request.user)
    if request.method == 'POST':
        form = FavoriteGroupForm(request.POST, instance=group)
        if form.is_valid():
            form.save()
            messages.success(request, _("Group renamed successfully!"))
            return redirect('catalog:manage-favorite-groups')
    else:
        form = FavoriteGroupForm(instance=group)
    return render(request, 'catalog/rename_favorite_group.html', {'form': form, 'group': group})

@login_required
def move_favorite_group(request, pk, direction):
    group = get_object_or_404(FavoriteGroup, pk=pk, user=request.user)
    if direction == 'up':
        prev_group = FavoriteGroup.objects.filter(user=request.user, order__lt=group.order).order_by('-order').first()
        if prev_group:
            group.order, prev_group.order = prev_group.order, group.order
            group.save()
            prev_group.save()
    elif direction == 'down':
        next_group = FavoriteGroup.objects.filter(user=request.user, order__gt=group.order).order_by('order').first()
        if next_group:
            group.order, next_group.order = next_group.order, group.order
            group.save()
            next_group.save()
    return redirect('catalog:manage-favorite-groups')

def public_favorite_group(request, uuid):
    group = get_object_or_404(FavoriteGroup, share_uuid=uuid)
    books = Book.objects.filter(favorites__group=group)
    return render(request, 'catalog/public_favorite_group.html', {'group': group, 'books': books})

@login_required
def my_favorites(request):
    sort = request.GET.get('sort', 'created_at')
    order = request.GET.get('order', 'desc')

    if sort == 'title':
        sort_field = 'title' if order == 'asc' else '-title'
    elif sort == 'author':
        sort_field = 'author' if order == 'asc' else '-author'
    else: # default to created_at
        sort_field = 'favorite_created_at' if order == 'asc' else '-favorite_created_at' # Updated sort field to annotated one

    # Handle batch unfavorite
    if request.method == 'POST' and 'batch_unfavorite' in request.POST:
        ids = request.POST.getlist('unfavorite_ids')
        BookFavorite.objects.filter(user=request.user, book_id__in=ids).delete()
        messages.success(request, f"成功取消收藏 {len(ids)} 本书。")
        return redirect('my-favorites')

    # Handle batch move
    if request.method == 'POST' and 'batch_move' in request.POST:
        ids = request.POST.getlist('unfavorite_ids')
        group_id = request.POST.get('move_group_id')
        group = None
        if group_id:
            group = FavoriteGroup.objects.filter(id=group_id, user=request.user).first()
        added = 0
        for book_id in ids:
            obj, created = BookFavorite.objects.get_or_create(book_id=book_id, user=request.user, defaults={'group': group})
            if not created and group and obj.group != group:
                obj.group = group
                obj.save()
            if created:
                added += 1
        if added:
            messages.success(request, f"成功收藏 {added} 本书！")
        else:
            messages.info(request, "所选书籍已全部在收藏夹中。")

    # Fetch favorite books for the current user and apply sorting
    user_favorite_entry = BookFavorite.objects.filter(
        book=OuterRef('pk'),
        user=request.user
    )

    books = Book.objects.filter(favorites__user=request.user)\
                    .annotate(\
                        favorite_group_id=Subquery(user_favorite_entry.values('group__id')[:1]),\
                        favorite_group_name=Subquery(\
                            FavoriteGroup.objects.filter(\
                                pk=OuterRef('favorite_group_id')\
                            ).values('name')[:1]
                        ),
                        favorite_created_at=Subquery(user_favorite_entry.values('created_at')[:1])
                    )\
                    .order_by(sort_field).distinct()

    # Add pagination
    paginator = Paginator(books, 6) # Display 6 favorite books per page
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    return render(request, 'catalog/my_favorites.html', {
        'page_obj': page_obj,
        'sort': sort,
        'order': order,
        'favorite_groups': request.user.favorite_groups.all(),
    })

@login_required
def export_favorites_csv(request):
    books = Book.objects.filter(favorites__user=request.user)
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="my_favorites.csv"'
    writer = csv.writer(response)
    writer.writerow(['Title', 'Author', 'ISBN'])
    for book in books:
        writer.writerow([book.title, str(book.author), book.isbn])
    return response

@login_required
def export_favorites_excel(request):
    books = Book.objects.filter(favorites__user=request.user)
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "My Favorites"
    headers = ['Title', 'Author', 'ISBN', 'Favorite Time', 'My Rating', 'Group']
    ws.append(headers)
    for book in books:
        favorite = book.favorites.filter(user=request.user).first()
        rating = book.ratings.filter(user=request.user).first()
        ws.append([
            book.title,
            str(book.author),
            book.isbn,
            favorite.created_at.strftime('%Y-%m-%d %H:%M') if favorite else '',
            rating.rating if rating else '',
            favorite.group.name if favorite and favorite.group else ''
        ])
    for col in range(1, len(headers) + 1):
        ws.column_dimensions[get_column_letter(col)].width = 20
    response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    response['Content-Disposition'] = 'attachment; filename=my_favorites.xlsx'
    wb.save(response)
    return response
from django.utils import translation
@login_required
def batch_favorite(request):
    if request.method == 'POST':
        ids = request.POST.getlist('favorite_ids')
        group_id = request.POST.get('group_id')
        group = None
        if group_id:
            from .models import FavoriteGroup
            group = FavoriteGroup.objects.filter(id=group_id, user=request.user).first()
        added = 0
        for book_id in ids:
            obj, created = BookFavorite.objects.get_or_create(book_id=book_id, user=request.user, defaults={'group': group})
            if not created and group and obj.group != group:
                obj.group = group
                obj.save()
            if created:
                added += 1
        if added:
            messages.success(request, f"成功收藏 {added} 本书！")
        else:
            messages.info(request, "所选书籍已全部在收藏夹中。")
    return redirect('catalog:books')

@login_required
def ai_chat_view(request):
    # 从数据库获取聊天历史
    chat_history = list(request.user.chat_messages.all().order_by('timestamp').values('role', 'content'))

    if request.method == 'POST':
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            data = json.loads(request.body)
            user_message_content = data.get('message')
            
            if user_message_content:
                # 保存用户消息到数据库
                ChatMessage.objects.create(user=request.user, role='user', content=user_message_content)
                # 将用户消息添加到当前会话的聊天历史中，以便传递给AI服务获取上下文
                chat_history.append({'role': 'user', 'content': user_message_content})
                
                # 获取AI响应，传递完整的聊天历史作为上下文
                ai_response_data = ai_service.get_chat_response(chat_history)
                
                if ai_response_data and ai_response_data.get('choices'):
                    ai_message_content = ai_response_data['choices'][0]['message']['content']
                    # 保存AI响应到数据库
                    ChatMessage.objects.create(user=request.user, role='assistant', content=ai_message_content)
                    return JsonResponse({'response': ai_message_content})
                else:
                    return JsonResponse({'error': 'Failed to get AI response.'}, status=500)
            else:
                return JsonResponse({'error': 'No message provided.'}, status=400)
        else:
            return redirect('catalog:ai_chat')
    
    # 对于GET请求，渲染聊天模板，并从数据库传递历史
    return render(request, 'catalog/ai_chat.html', {'chat_history': chat_history})

@login_required
def clear_chat_history(request):
    # 从数据库中删除用户的聊天历史
    request.user.chat_messages.all().delete()
    messages.success(request, "Chat history cleared.")
    
    if request.headers.get('x-requested-with') == 'XMLHttpRequest':
        return JsonResponse({'status': 'success', 'message': 'Chat history cleared.'})
    else:
        return redirect('catalog:ai_chat')

@login_required
def rate_book(request, pk):
    book_id = get_object_or_404(Book, pk=pk)

    if request.method == 'POST':
        rating_value = request.POST.get('rating')
        if rating_value is not None:
            try:
                rating_value = int(rating_value)
                if 1 <= rating_value <= 5:
                    BookRating.objects.update_or_create(
                        book=book_id, user=request.user,
                        defaults={'rating': rating_value}
                    )
                    return JsonResponse({'message': 'Rating updated successfully.'})
                else:
                    return JsonResponse({'error': 'Rating must be between 1 and 5.'}, status=400)
            except ValueError:
                return JsonResponse({'error': 'Invalid rating value.'}, status=400)
        else:
            return JsonResponse({'error': 'No rating provided.'}, status=400)
    return JsonResponse({'error': 'Invalid request method.'}, status=405)

@login_required
def add_favorite_group(request):
    if request.method == 'POST':
        form = FavoriteGroupForm(request.POST)
        if form.is_valid():
            group = form.save(commit=False)
            group.user = request.user
            group.save()
            messages.success(request, _("Favorite group created successfully!"))
        else:
            for field, errors in form.errors.items():
                for error in errors:
                    messages.error(request, f"{field}: {error}")
    return redirect('manage-favorite-groups')

@login_required
def profile_edit(request):
    profile = request.user.profile
    if request.method == 'POST':
        print(f"POST request received for profile edit. Request FILES: {request.FILES}")
        form = ProfileForm(request.POST, request.FILES, instance=profile)
        if form.is_valid():
            print("ProfileForm is valid. Attempting to save.")
            form.save()
            print("Profile saved successfully!")
            messages.success(request, 'Your profile was successfully updated!')
            # For AJAX requests, return a success response, otherwise redirect
            if request.headers.get('x-requested-with') == 'XMLHttpRequest':
                print("AJAX POST request received in profile_edit view. Rendering profile_edit.html.")
                return render(request, 'catalog/profile_edit.html', {'form': form})
            return redirect('catalog:profile_edit') # Redirect to the full page version
        else:
            print(f"ProfileForm is NOT valid. Errors: {form.errors}")
            # If form is not valid, re-render the form with errors
            if request.headers.get('x-requested-with') == 'XMLHttpRequest':
                print("AJAX POST request with invalid form. Rendering profile_edit.html with errors.")
                return render(request, 'catalog/profile_edit.html', {'form': form})
            else:
                print("Regular POST request with invalid form. Rendering profile_edit_full.html with errors.")
                return render(request, 'catalog/profile_edit_full.html', {'form': form})
    else:
        form = ProfileForm(instance=profile)
    
    # Check if it's an AJAX request (e.g., from fetch API)
    if request.headers.get('x-requested-with') == 'XMLHttpRequest':
        print("AJAX GET request received in profile_edit view. Rendering profile_edit.html.")
        return render(request, 'catalog/profile_edit.html', {'form': form})
    else:
        print("Regular GET request received in profile_edit view. Rendering profile_edit_full.html.")
        return render(request, 'catalog/profile_edit_full.html', {'form': form})

# Signal to create a Profile for new Users
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        try:
            Profile.objects.get_or_create(user=instance)
        except:
            pass

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    try:
        if hasattr(instance, 'profile'):
            instance.profile.save()
        else:
            Profile.objects.get_or_create(user=instance)
    except:
        pass

@login_required
def book_statistics_view(request):
    total_books = Book.objects.count()
    from django.db.models import OuterRef, Subquery
    latest_instances = BookInstance.objects.filter(book=OuterRef('pk')).order_by('-due_back')
    borrowed_books = Book.objects.annotate(
        latest_status=Subquery(latest_instances.values('status')[:1])
    ).filter(latest_status='o').count()
    
    borrowed_percentage = 0
    if total_books > 0:
        borrowed_percentage = (borrowed_books / total_books) * 100

    # Get book counts by genre
    books_by_genre = Book.objects.values('genre__name').annotate(count=Count('id')).order_by('genre__name')
    genre_labels = [item['genre__name'] for item in books_by_genre if item['genre__name'] is not None]
    genre_counts = [item['count'] for item in books_by_genre if item['genre__name'] is not None]

    context = {
        'total_books': total_books,
        'borrowed_books': borrowed_books,
        'borrowed_percentage': round(borrowed_percentage, 2),
        'genre_labels': json.dumps(genre_labels),
        'genre_counts': json.dumps(genre_counts),
    }
    return render(request, 'catalog/book_statistics.html', context)

@login_required
def borrow_book(request, pk):
    """View function for borrowing a book."""
    book_instance = get_object_or_404(BookInstance, pk=pk)
    
    # Check if book is available
    if book_instance.is_borrowed:
        messages.error(request, 'This book is already borrowed.')
        return redirect('catalog:book-detail', pk=book_instance.book.pk)
    
    # Set book as borrowed
    book_instance.is_borrowed = True
    book_instance.borrower = request.user
    book_instance.due_back = datetime.datetime.now() + datetime.timedelta(days=14)  # 2 weeks loan period
    book_instance.status = 'o'  # On loan
    book_instance.save()
    
    messages.success(request, f'You have successfully borrowed {book_instance.book.title}.')
    return redirect('catalog:book-detail', pk=book_instance.book.pk)

@login_required
def return_book(request, pk):
    """View function for returning a book."""
    book_instance = get_object_or_404(BookInstance, pk=pk)
    
    # Check if book is borrowed by the current user
    if not book_instance.is_borrowed or book_instance.borrower != request.user:
        messages.error(request, 'You cannot return this book.')
        return redirect('catalog:book-detail', pk=book_instance.book.pk)
    
    # Set book as returned
    book_instance.is_borrowed = False
    book_instance.borrower = None
    book_instance.due_back = None
    book_instance.status = 'a'  # Available
    book_instance.save()
    
    messages.success(request, f'You have successfully returned {book_instance.book.title}.')
    return redirect('catalog:book-detail', pk=book_instance.book.pk)
